package com.koron.common.core.business.configsettings.service;

import com.koron.bean.base.Response;
import com.koron.bean.util.RedisUtils;
import com.koron.common.core.business.configsettings.bean.ConfigDetail;
import com.koron.common.core.business.configsettings.bean.ConfigType;
import com.koron.common.core.business.configsettings.bean.ConfigTypeQuery;
import com.koron.common.core.business.configsettings.mapper.ConfigTypeMapper;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.UpdateRedis;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * 系统管理-配置分类{@code ConfigType}服务实现类
 *
 * <p>方法1-checkBeforeInsert：新增单条数据</p>
 * <p>方法2-checkBeforeDelete：逻辑删除单条数据</p>
 * <p>方法3-checkBeforeUpdate：更新单条数据</p>
 * <p>方法4-getListAndPaging：根据条件查询数据，并分页</p>
 * <p>方法5-getByClassifyCodeAndCode：根据classifyCode和code查询单条配置项数据及其配置详情</p>
 * <p>方法6-getById：根据id查询单条配置项</p>
 *
 * @author 朱超
 * @since 2021-09-01
 */
@Service
public class ConfigTypeService {

    @Autowired
    private UpdateRedis updateRedis;

    @Autowired
    private ConfigDetailService configDetailService;

    private static final String KEY_PREFIX = "eam:configSettings:";

    /**
     * 新增单条数据
     *
     * @param factory
     * @param configType:至少包含classifyCode,code,name
     * @return Response对象
     * @throws {@code Internal Server Error} 配置编码不能重复
     * @throws {@code Internal Server Error} 配置名称不能重复
     * @version 1.0
     * @see Response
     */
    @TaskAnnotation("checkBeforeInsert")
    public Response checkBeforeInsert(SessionFactory factory, ConfigType configType) {
        ConfigTypeMapper configTypeMapper = factory.getMapper(ConfigTypeMapper.class);
        String code = configType.getCode();
        String name = configType.getName();

        // 1. 判断配置编码是否重复
        ConfigType uniqueCode = configTypeMapper.getByCode(code);
        if (uniqueCode != null) {
            return Response.fail("配置编码不能重复!");
        }
        // 2. 判断配置名称是否重复
        ConfigType uniqueName = configTypeMapper.getByName(name);
        if (uniqueName != null) {
            return Response.fail("配置名称不能重复");
        }
        // 3. 添加id
        configType.setId(CodeTools.getCode32());
        // 4. 添加deleteFlag
        configType.setDeleteFlag(0);
        // 5. 添加数据
        configTypeMapper.insert(configType);
        // 6. redis添加数据
        updateRedis.setConfigTypeInRedis(configType);

        return Response.success("新增成功");
    }

    /**
     * 逻辑删除单条数据
     *
     * @param factory
     * @param id
     * @return Response
     * @throws {@code Internal Server Error} 该配置项下仍有配置详情，无法删除
     * @version 1.0
     * @see Response
     */
    @TaskAnnotation("checkBeforeDelete")
    public Response checkBeforeDelete(SessionFactory factory, String id) {
        ConfigTypeMapper configTypeMapper = factory.getMapper(ConfigTypeMapper.class);

        // 1. 根据id查出对应数据
        ConfigType configType = configTypeMapper.getById(id);
        // 2. 判断配置分类下是否还有配置详情
        List<ConfigDetail> configDetailList = configDetailService.getListByConfigId(factory, id);
        if (configDetailList.size() > 0) {
            return Response.fail("该配置项下仍有配置详情，无法删除");
        }
        // 3. 获取redisKey，用于redis中删除该数据
        String classifyCode = configType.getClassifyCode();
        String code = configType.getCode();
        String redisKey = KEY_PREFIX + classifyCode + ":" + code;
        // 4. 逻辑删除单条数据
        configType.setDeleteFlag(1);
        configTypeMapper.update(configType);
        // 5. redis删除数据
        RedisUtils.delete(redisKey);

        return Response.success("删除成功");
    }

    /**
     * 更新单条数据
     *
     * @param factory
     * @param configType
     * @return Response
     * @throws {@code Internal Server Error} 配置编码不能重复
     * @throws {@code Internal Server Error} 配置名称不能重复
     * @version 1.0
     * @see Response
     */
    @TaskAnnotation("checkBeforeUpdate")
    public Response checkBeforeUpdate(SessionFactory factory, ConfigType configType) {
        ConfigTypeMapper configTypeMapper = factory.getMapper(ConfigTypeMapper.class);
        String code = configType.getCode();
        String name = configType.getName();
        String id = configType.getId();

        // 1. 判断配置编码是否重复，将自身排除
        ConfigType uniqueCode = configTypeMapper.getByCode(code);
        if (uniqueCode != null && !uniqueCode.getId().equals(id)) {
            return Response.fail("配置编码不能重复!");
        }
        // 2. 判断配置名称是否重复，将自身排除
        ConfigType uniqueName = configTypeMapper.getByName(name);
        if (uniqueName != null && !uniqueName.getId().equals(id)) {
            return Response.fail("配置名称不能重复");
        }
        // 3. 通过了前面的判断，说明可以更新...如果更新了配置编码，因为redisKey的生成规则，需要把redis中原来的数据删除
        // 3.1 查出未更新的数据，主要是code
        ConfigType formerConfigType = configTypeMapper.getById(id);
        String formerCode = formerConfigType.getCode();
        // 3.2 只有当配置编码变更的时候，redisKey才会变更
        if (!formerCode.equals(code)) {
            // 3.3 获取变更前的redisKey，并删除
            String formerRedisKey = KEY_PREFIX + formerConfigType.getClassifyCode() + ":" + formerCode;
            RedisUtils.delete(formerRedisKey);
        }
        // 4. 更新数据
        configTypeMapper.update(configType);
        // 5. redis更新数据
        // 5.1 获取对应的配置详情
        List<ConfigDetail> configDetailList = configDetailService.getListByConfigId(factory, id);
        configType.setConfigDetailList(configDetailList);
        // 5.2 redis更新
        updateRedis.setConfigTypeInRedis(configType);

        return Response.success("更新成功");
    }

    /**
     * 根据条件查询数据，并分页
     *
     * @param factory
     * @param classifyCode
     * @param code
     * @param name
     * @param page
     * @param pageSize
     * @return Response
     * @version 1.0
     * @see Response
     */
    @TaskAnnotation("getListAndPaging")
    public Response getListAndPaging(SessionFactory factory, String classifyCode, String code, String name, Integer page, Integer pageSize) {
        ConfigTypeMapper configTypeMapper = factory.getMapper(ConfigTypeMapper.class);
        ConfigTypeQuery configTypeQuery = new ConfigTypeQuery();

        // 1. 构造请求实例
        configTypeQuery.setClassifyCode(classifyCode);
        configTypeQuery.setCode(code);
        configTypeQuery.setName(name);
        configTypeQuery.setPage(page);
        configTypeQuery.setPageSize(pageSize);

        // 2. 根据分页条件查询对应的数据
        List<ConfigType> configTypeList = configTypeMapper.getListAndPaging(configTypeQuery);
        // 3. 查询符合条件的总数
        Integer count = configTypeMapper.count(configTypeQuery);

        return Response.success(configTypeList, count.longValue());

    }

    /**
     * 根据classifyCode和code查询单条配置项数据及其配置详情
     *
     * @param factory
     * @param classifyCode
     * @param code
     * @return ConfigType
     * @version 1.0
     * @see ConfigType
     */
    @TaskAnnotation("getByClassifyCodeAndCode")
    public ConfigType getByClassifyCodeAndCode(SessionFactory factory, String classifyCode, String code) {
        ConfigType configType = null;

        // 1. 定义redisKey
        String redisKey = KEY_PREFIX + classifyCode + ":" + code;
        // 2. 尝试从redis中获取数据
        boolean redisable = RedisUtils.getRedisTemplate() != null;
        Map<Object, Object> redisValue;
        if (redisable && (redisValue = RedisUtils.hmget(redisKey)).size() != 0) {
            configType = new ConfigType();
            // 3. 将redis中获取的数据赋值到实例中
            configType.setId((String) redisValue.get("id"));
            configType.setClassifyCode((String) redisValue.get("classifyCode"));
            configType.setCode((String) redisValue.get("code"));
            configType.setName((String) redisValue.get("name"));
            configType.setConfigDetailList((List<ConfigDetail>) redisValue.get("configDetailList"));
        } else {
            // 4. 如果redis中获取不到，则从数据库获取
            ConfigTypeMapper configTypeMapper = factory.getMapper(ConfigTypeMapper.class);
            configType = configTypeMapper.getByClassifyCodeAndCode(classifyCode, code);
            if (configType == null) {
                return null;
            }
            // 4.1 根据configId将相关的详情查出来
            String id = configType.getId();
            List<ConfigDetail> configDetailList = configDetailService.getListByConfigId(factory, id);
            configType.setConfigDetailList(configDetailList);
            // 5. redis添加数据
            if (redisable) {
                updateRedis.setConfigTypeInRedis(configType);
            }
        }

        return configType;
    }

    /**
     * 根据id查询单条配置项
     *
     * @param factory
     * @param id
     * @return ConfigType
     * @version 1.0
     * @see ConfigType
     */
    public ConfigType getById(SessionFactory factory, String id) {
        ConfigTypeMapper configTypeMapper = factory.getMapper(ConfigTypeMapper.class);
        return configTypeMapper.getById(id);
    }

}
